home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Source.bin / BaseTabbedPanel.java < prev    next >
Text File  |  1998-08-21  |  45KB  |  1,707 lines

  1. /*
  2.  Copyright (c) 1995, 1996 Connect! Corporation, Inc. All Rights Reserved.
  3.  Source code usage restricted as defined in Connect! Widgets License Agreement
  4. */
  5.  
  6. package symantec.itools.awt;
  7.  
  8.  
  9. import java.awt.*;
  10. import java.applet.Applet;
  11. import java.util.Vector;
  12. import java.beans.PropertyVetoException;
  13. import java.beans.PropertyChangeListener;
  14. import java.beans.VetoableChangeListener;
  15. import java.awt.event.MouseEvent;
  16. import java.awt.event.ActionEvent;
  17. import java.awt.event.ActionListener;
  18. import symantec.itools.awt.util.ColorUtils;
  19. import symantec.itools.awt.*;
  20.  
  21.  
  22. //    05/07/97    LAB    Updated to support Java 1.1
  23. //    06/05/97    LAB    Made all private variables used in the innerclasses, protected.
  24. //    06/05/97    LAB    Updated deprecated calls to DirectionButton's enable and disable
  25. //                    methods to the new setEnabled(boolean).
  26. //    07/19/97    LAB    Added add/removeNotify for event listener registration. Updated deprecated
  27. //                    preferredSize and minimumSize calls.  Added a version tag
  28. //  07/25/97    CAR marked fields transient as needed
  29. //                  innerclasses implement java.io.Serializable
  30. //    08/13/97    LAB    Now draws the borders with colors calculated from the backround color, and
  31. //                    draws the text with colors calculated from the foreground color.  This
  32. //                    addresses Mac Bug #7189.  Removed unneeded imports.
  33. //    08/15/97    LAB    Reworked the way colors were calculated to avoid NullPointerExceptions,
  34. //                    and potential redraw problems.  Now colors are recalculated in paint,
  35. //                    if needed.
  36. //    08/21/97    RKM    Added setSuppressRepaints, bottle necked repaint calls for better redraws
  37. //                    Used setSuppressRepaints in setCurrentTab
  38. //  08/28/97    CAR can now specify an index position for addTab
  39. //  12/09/97    JYZ now can change the font size of the tab labels. This addresses bug #5234.
  40.  
  41. /**
  42.  * BaseTabbedPanel is a Panel extension which provides for
  43.  * a tabbed dialog effect. It provides the visual aspect of
  44.  * tabs and allows the programmer to decide what action to take
  45.  * when a tab is activated. It can be used directly or extended.
  46.  * When extending from BaseTabbedPanel be sure to super()
  47.  * during construction and to super.handleEvent(evt) from
  48.  * handleEvent if you override it.
  49.  * <p>
  50.  * To add a new tab to the panel use the addTab() method. To update an
  51.  * existing tab use the setLabel() or setTab() method. To remove tabs
  52.  * use the removeTab() or removeAllTabs() method.
  53.  * <p>
  54.  * To enable or disable a tab use the setEnabled() method.
  55.  * <p>
  56.  * To show (activate) a tab use the showTab() method.
  57.  * @author Symantec
  58.  * @author Scott Fauerbach
  59.  * @version 1.1, July 19, 1997
  60.  */
  61. public abstract class BaseTabbedPanel extends Panel
  62. {
  63.     /**
  64.      * Position constant indicating tabs are to be put at the top of this panel.
  65.      */
  66.     public static final int TOP = 0;
  67.  
  68.     /**
  69.      * Position constant indicating tabs are to be put at the bottom of this panel.
  70.      */
  71.     public static final int BOTTOM = 1;
  72.  
  73.     /**
  74.      * Style constant indicating tabs are to have rounded corners.
  75.      */
  76.     public static final int ROUNDED = 0;
  77.  
  78.     /**
  79.      * Style constant indicating tabs are to have square corners.
  80.      */
  81.     public static final int SQUARE = 1;
  82.  
  83.  
  84.     /**
  85.      * Constructs a BaseTabbedPanel with tabs on top and rounded.
  86.      */
  87.     public BaseTabbedPanel()
  88.     {
  89.         this(TOP, ROUNDED);
  90.     }
  91.  
  92.     /**
  93.      * @deprecated
  94.      * @see BaseTabbedPanel#BaseTabbedPanel(int, int)
  95.      */
  96.     public BaseTabbedPanel(boolean bTabsOnTop)
  97.     {
  98.         this(bTabsOnTop ? TOP : BOTTOM, bTabsOnTop ? ROUNDED : SQUARE);
  99.     }
  100.  
  101.     /**
  102.      * Constructs a BaseTabbedPanel with the desired tab position
  103.      * and corner style.
  104.      * @param tabsPostion a constant indicating TOP or BOTTOM tab location
  105.      * @param tabsStyle a constant indicating ROUNDED or SQUARE tabs
  106.      */
  107.     public BaseTabbedPanel(int tabsPostion, int tabsStyle)
  108.     {
  109.         vLabels = new Vector();
  110.         vEnabled = new Vector();
  111.         vPolys = new Vector();
  112.         btpInsets = new Insets(0,0,0,0);
  113.  
  114.         setTabsInfo(tabsPostion, tabsStyle);
  115.  
  116.         fReg = new Font("SansSerif", Font.PLAIN, 12);
  117.         fSel = new Font("SansSerif", Font.BOLD, 12);
  118.  
  119.         if (System.getProperty("os.name").startsWith("S")) // SunOS, Solaris
  120.             osAdjustment = -1;
  121.         else
  122.             osAdjustment = 0;
  123.  
  124.         super.setLayout(null);
  125.  
  126.         // prepare left/right arrows
  127.         dbLeft = new DirectionButton(DirectionButton.LEFT);
  128.         dbRight = new DirectionButton(DirectionButton.RIGHT);
  129.         try
  130.         {
  131.             dbLeft.setShowFocus(false);
  132.             dbRight.setShowFocus(false);
  133.         }
  134.         catch(PropertyVetoException e){}
  135.  
  136.         dbLeft.shrinkTriangle(1, 1, 0, 1);
  137.         dbRight.shrinkTriangle(1, 1, 0, 1);
  138.         super.add(dbLeft, -1);
  139.         super.add(dbRight, -1);
  140.  
  141.         nullPoly = new Polygon();
  142.         nullPoly.addPoint(0, 0);
  143.         nullPoly.addPoint(1, 1);
  144.         nullPoly.addPoint(0, 0);
  145.  
  146.         //Initilize the cached colors.
  147.         cachedForeground    = getForeground();
  148.         cachedBackground    = getBackground();
  149.     }
  150.  
  151.     /**
  152.      * Sets the position of the all tabs to the top or bottom of this panel.
  153.      * Note that if the tabs are on top they are always rounded.
  154.      * @param tabsPosition constant indicating TOP or BOTTOM
  155.      * @exception PropertyVetoException
  156.      * if the specified property value is unacceptable
  157.      * @see getTabsPosition
  158.      * @see #TOP
  159.      * @see #BOTTOM
  160.      */
  161.     public void setTabsPosition(int tabsPosition) throws PropertyVetoException
  162.     {
  163.         if (iTabsPosition != tabsPosition)
  164.         {
  165.             Integer oldValue = new Integer(iTabsPosition);
  166.             Integer newValue = new Integer(tabsPosition);
  167.  
  168.             vetos.fireVetoableChange("TabsPosition", oldValue, newValue);
  169.  
  170.             setTabsInfo(tabsPosition, iTabsStyle);
  171.  
  172.             changes.firePropertyChange("TabsPosition", oldValue, newValue);
  173.         }
  174.     }
  175.  
  176.     /**
  177.      * Gets the current tabs position, TOP or BOTTOM.
  178.      * @return the position constant TOP or BOTTOM, indicating the current tabs position
  179.      * @see setTabsPosition
  180.      * @see #TOP
  181.      * @see #BOTTOM
  182.      */
  183.     public int getTabsPosition()
  184.     {
  185.          return iTabsPosition;
  186.     }
  187.  
  188.     /**
  189.      * Sets the style of the tabs to ROUNDED or SQUARE.
  190.      * Note that if the tabs are on top they are always rounded.
  191.      * @param tabsStyle a constant indicating ROUNDED or SQUARE
  192.      * @exception PropertyVetoException
  193.      * if the specified property value is unacceptable
  194.      * @see getTabsStyle
  195.      * @see #ROUNDED
  196.      * @see #SQUARE
  197.      */
  198.     public void setTabsStyle(int tabsStyle) throws PropertyVetoException
  199.     {
  200.         if (iTabsStyle != tabsStyle)
  201.         {
  202.             Integer oldValue = new Integer(iTabsStyle);
  203.             Integer newValue = new Integer(tabsStyle);
  204.  
  205.             vetos.fireVetoableChange("TabsStyle", oldValue, newValue);
  206.  
  207.             setTabsInfo(iTabsPosition, tabsStyle);
  208.  
  209.             changes.firePropertyChange("TabsStyle", oldValue, newValue);
  210.         }
  211.     }
  212.  
  213.     /**
  214.      * Gets the current tab style, ROUNDED or SQUARE.
  215.      * @return the style constant ROUNDED or SQUARE, indicating the current tab style
  216.      * @see setTabsStyle
  217.      * @see #ROUNDED
  218.      * @see #SQUARE
  219.      */
  220.     public int getTabsStyle()
  221.     {
  222.         return iTabsStyle;
  223.     }
  224.  
  225.     /**
  226.      * Sets the position and style of all the tabs.
  227.      * Note that if the tabs are on top they are always rounded.
  228.      * @param tabsPosition a constant indicating TOP or BOTTOM
  229.      * @param tabsStyle a constant indicating ROUNDED or SQUARE
  230.      * @see getTabsPosition
  231.      * @see getTabsStyle
  232.      * @see #TOP
  233.      * @see #BOTTOM
  234.      * @see #ROUNDED
  235.      * @see #SQUARE
  236.      */
  237.     public void setTabsInfo(int tabsPosition, int tabsStyle)
  238.     {
  239.         iTabsPosition = tabsPosition;
  240.         if (iTabsPosition == TOP)
  241.             iTabsStyle = ROUNDED;
  242.         else
  243.             iTabsStyle = tabsStyle;
  244.  
  245.         if (iTabsStyle == ROUNDED)
  246.             TF_BTN_HEIGHT = 20;
  247.         else
  248.             TF_BTN_HEIGHT = 17;
  249.  
  250.         triggerRepaint();
  251.     }
  252.  
  253.     /**
  254.      * Sets whether to suppress repainting when making changes to this component
  255.      * that affect its display. If <code>false</code> method calls that might change
  256.      * the appearance of this component automatically repaint the component.
  257.      * If <code>true</code> those repaints are prevented.
  258.      * @param b <code>true</code> to prevent repaints, <code>false</code> to repaint
  259.      * anytime it might be needed.
  260.      * @return the previous value of the suppress repaints flag
  261.      */
  262.     public boolean setSuppressRepaints(boolean b)
  263.     {
  264.         boolean wasSuppressingRepaints = suppressRepaints;
  265.         suppressRepaints = b;
  266.         return wasSuppressingRepaints;
  267.     }
  268.  
  269.     /**
  270.      * Helper method to trigger a repaint if it hasn't been suppressed.
  271.      * @see #setSuppressRepaints
  272.      */
  273.     protected void triggerRepaint()
  274.     {
  275.         if (!suppressRepaints)
  276.             repaint();
  277.     }
  278.  
  279.     /**
  280.      * Adds the panel to the base panel and shows it.
  281.      * Removes all other previous panels from base panel.
  282.      * @param p the panel to add and show
  283.      * @exception PropertyVetoException
  284.      * if the specified property value is unacceptable
  285.      */
  286.     public void setPanel(Component p) throws PropertyVetoException
  287.     {
  288.         Component oldValue = userPanel;
  289.  
  290.         vetos.fireVetoableChange("Panel", oldValue, p);
  291.  
  292.         removeAll();
  293.         userPanel = p;
  294.         if (userPanel != null)
  295.         {
  296.             super.add(userPanel, -1);
  297.             userPanel.requestFocus();
  298.         }
  299.  
  300.         changes.firePropertyChange("Panel", oldValue, p);
  301.     }
  302.  
  303.     /**
  304.      * Labels and conditionally enables the tab at the specified index.
  305.      * @param sLabel the tab label
  306.      * @param bEnabled enable the tab or not
  307.      * @param index the zero-relative index of the tab
  308.      * @exception PropertyVetoException
  309.      * if the specified property value is unacceptable
  310.      * @see #addTab
  311.      * @see #setLabel
  312.      */
  313.     public synchronized void setTab(String sLabel, boolean bEnabled, int index) throws PropertyVetoException
  314.     {
  315.         boolean wasSuppressingRepaints = setSuppressRepaints(true);
  316.  
  317.         try
  318.         {
  319.             setLabel(sLabel, index);
  320.             setEnabled(bEnabled, index);
  321.         }
  322.         finally
  323.         {
  324.             setSuppressRepaints(wasSuppressingRepaints);
  325.         }
  326.  
  327.         triggerRepaint();
  328.     }
  329.  
  330.     /**
  331.      * Changes the label of the tab at the specified index.
  332.      * @param sLabel the new label for the specified tab
  333.      * @param index the zero-relative index of the tab
  334.      * @exception PropertyVetoException
  335.      * if the specified property value is unacceptable
  336.      * @see #getLabel
  337.      * @see #addTab
  338.      * @see #setTab
  339.      */
  340.     public synchronized void setLabel(String sLabel, int index) throws PropertyVetoException
  341.     {
  342.         if ((index < 0) || (index >= vLabels.size()))
  343.             return;
  344.  
  345.         try
  346.         {
  347.             String oldValue = (String) vLabels.elementAt(index);
  348.             vetos.fireVetoableChange("Label", oldValue, sLabel);
  349.  
  350.             vLabels.setElementAt(sLabel, index);
  351.             triggerRepaint();
  352.  
  353.             changes.firePropertyChange("Label", oldValue, sLabel);
  354.         }
  355.         catch (ArrayIndexOutOfBoundsException e) {}
  356.     }
  357.  
  358.     /**
  359.      * Gets the label of the tab at the specified index.
  360.      * @param index the zero-relative index of the tab
  361.      * @return the tab label
  362.      * @see #setLabel
  363.      */
  364.     public synchronized String getLabel(int index)
  365.     {
  366.         if ((index < 0) || (index >= vLabels.size()))
  367.             return "";
  368.  
  369.         try
  370.         {
  371.             return (String)vLabels.elementAt(index);
  372.         }
  373.         catch (ArrayIndexOutOfBoundsException e) {}
  374.         return "";
  375.     }
  376.  
  377.     /**
  378.      * Conditionally enables the tab at the specified index.
  379.      * The currently active tab cannot be disabled.
  380.      * This performs the same action as enableTab().
  381.      * @param bEnable true to enable, false to disable
  382.      * @param index the zero-relative index of the tab
  383.      * @exception PropertyVetoException
  384.      * if the specified property value is unacceptable
  385.      */
  386.     public synchronized void setEnabled(boolean bEnabled, int index) throws PropertyVetoException
  387.     {
  388.         if ((index < 0) || (index >= vLabels.size()))
  389.             return;
  390.  
  391.         if (index == curIndex && !bEnabled)
  392.             return;
  393.  
  394.         try
  395.         {
  396.             Boolean oldValue = (Boolean) vEnabled.elementAt(index);
  397.             Boolean newValue = new Boolean(bEnabled);
  398.  
  399.             vetos.fireVetoableChange("Enabled", oldValue, newValue);
  400.  
  401.             vEnabled.setElementAt(newValue, index);
  402.             triggerRepaint();
  403.  
  404.             changes.firePropertyChange("Enabled", oldValue, newValue);
  405.         }
  406.         catch (ArrayIndexOutOfBoundsException e) {}
  407.     }
  408.  
  409.     /**
  410.      * Determines whether or not the tab at the index is enabled.
  411.      * @param index the zero-relative index of the tab
  412.      * @return true if the tab at the index is enabled
  413.      */
  414.     public boolean isEnabled(int index)
  415.     {
  416.         if ((index < 0) || (index >= vLabels.size()))
  417.             return false;
  418.  
  419.         try
  420.         {
  421.             Boolean bool = (Boolean) vEnabled.elementAt(index);
  422.             if (bool.booleanValue())
  423.                 return true;
  424.         }
  425.         catch (ArrayIndexOutOfBoundsException e) {}
  426.  
  427.         return false;
  428.     }
  429.  
  430.  
  431.     /**
  432.      * Shows the tab at the specified index. The tab must be enabled for
  433.      * it to be shown.
  434.      * @param index the zero-relative index of the tab to show
  435.      * @exception PropertyVetoException
  436.      * if the specified property value is unacceptable
  437.      * @see #getCurrentTab
  438.      */
  439.     public void setCurrentTab(int index) throws PropertyVetoException
  440.     {
  441.         if ((index < 0) || (index >= vLabels.size()) || index == curIndex)
  442.             return;
  443.  
  444.         if ( isEnabled(index) )
  445.         {
  446.             boolean wasSuppressingRepaints = setSuppressRepaints(true);
  447.  
  448.             try
  449.             {
  450.                 Integer oldValue = new Integer(curIndex);
  451.                 Integer newValue = new Integer(index);
  452.  
  453.                 vetos.fireVetoableChange("CurrentTab", oldValue, newValue);
  454.                 curIndex = index;
  455.                 firstVisibleTab = calculateMakeTabVisible(index);
  456.                 changes.firePropertyChange("CurrentTab", oldValue, newValue);
  457.             }
  458.             finally
  459.             {
  460.                 setSuppressRepaints(wasSuppressingRepaints);
  461.             }
  462.  
  463.             triggerRepaint();
  464.         }
  465.     }
  466.  
  467.     /**
  468.      * Determine the currently shown tab.
  469.      * @return zero-relative index of the currently shown tab
  470.      * @see #setCurrentTab(int)
  471.      */
  472.     public int getCurrentTab()
  473.     {
  474.         return curIndex;
  475.     }
  476.  
  477.     /**
  478.      * @deprecated
  479.      * @see #setEnabled(boolean, int)
  480.      * @exception PropertyVetoException
  481.      * if the specified property value is unacceptable
  482.      */
  483.     public void enableTab(boolean bEnabled, int index) throws PropertyVetoException
  484.     {
  485.         setEnabled(bEnabled, index);
  486.     }
  487.  
  488.     /**
  489.      * @deprecated
  490.      * @see #isEnabled(int)
  491.      */
  492.     public boolean tabIsEnabled(int index)
  493.     {
  494.         return(isEnabled(index));
  495.     }
  496.  
  497.     /**
  498.      * Adds the panel to the base panel and shows it.
  499.      * Hides all other (previous) panels instead of removing them.
  500.      * @param p the Panel to add and show
  501.      */
  502.     public void showPanel(Component p)
  503.     {
  504.         if (userPanel != null)
  505.             userPanel.hide();
  506.  
  507.         userPanel = p;
  508.         if (userPanel != null)
  509.         {
  510.             Component[] comps = getComponents();
  511.             int l = comps.length;
  512.             int x;
  513.             for (x = 0; x < l; x++)
  514.             {
  515.                 if (comps[x] == userPanel)
  516.                     break;
  517.             }
  518.             if (x == l)
  519.                 super.add(userPanel, -1);
  520.  
  521.             userPanel.show();
  522.             userPanel.requestFocus();
  523.             validate();
  524.             triggerRepaint();
  525.         }
  526.     }
  527.  
  528.     /**
  529.      * Appends a new tab and sets whether it is enabled.
  530.      * @param sLabel the tab label
  531.      * @param bEnabled enable the tab or not
  532.      * @return the zero-relative index of the newly added tab
  533.      * @see #setTab
  534.      * @see #setLabel
  535.      */
  536.     public int addTab(String sLabel, boolean bEnabled)
  537.     {
  538.         return addTab(sLabel, bEnabled, -1);
  539.     }
  540.  
  541.     /**
  542.      * Adds a new tab at the specified position and sets whether it is enabled.
  543.      * @param sLabel the tab label
  544.      * @param bEnabled enable the tab or not
  545.      * @param pos the zero-relative index for the new tab
  546.      * @return the zero-relative index of the newly added tab
  547.      * @see #setTab
  548.      * @see #setLabel
  549.      */
  550.     public int addTab(String sLabel, boolean bEnabled, int pos)
  551.     {
  552.         int index;
  553.  
  554.         if (pos == -1) {
  555.         vLabels.addElement(sLabel);
  556.         vEnabled.addElement(new Boolean(bEnabled));
  557.         index = vLabels.size() - 1;
  558.         }
  559.         else {
  560.         vLabels.insertElementAt(sLabel, pos);
  561.         vEnabled.insertElementAt(new Boolean(bEnabled), pos);
  562.         index = pos;
  563.         }
  564.         if (curIndex == -1 && bEnabled)
  565.         {
  566.             try
  567.             {
  568.                 setCurrentTab(index);
  569.             }
  570.             catch (PropertyVetoException e)
  571.             {
  572.                 //Return an error state
  573.                 index = -1;
  574.             }
  575.         }
  576.         return (index);
  577.     }
  578.  
  579.     /**
  580.      * @deprecated
  581.      * @see #setCurrentTab(int)
  582.      * @exception PropertyVetoException
  583.      * if the specified property value is unacceptable
  584.      */
  585.     public void showTab(int index) throws PropertyVetoException
  586.     {
  587.         setCurrentTab(index);
  588.     }
  589.  
  590.     /**
  591.      * @deprecated
  592.      * @see #getCurrentTab
  593.      */
  594.     public int currentTabIndex()
  595.     {
  596.         return getCurrentTab();
  597.     }
  598.  
  599.     /**
  600.      * Inserts a tab before the tab at the specified index.
  601.      * @param sLabel label of the new tab to insert
  602.      * @param bEnabled enable the tab or not
  603.      * @param index the zero-relative index at which the tab will be inserted.
  604.      */
  605.     public synchronized void insertTab(String sLabel, boolean bEnabled, int index)
  606.     {
  607.         if ((index < 0) || (index >= vLabels.size()))
  608.             return;
  609.  
  610.         if (index == curIndex && !bEnabled)
  611.             return;
  612.  
  613.         try
  614.         {
  615.             vLabels.insertElementAt(sLabel, index);
  616.             vEnabled.insertElementAt(new Boolean(bEnabled), index);
  617.             triggerRepaint();
  618.         }
  619.         catch (ArrayIndexOutOfBoundsException e) {}
  620.     }
  621.  
  622.     /**
  623.      * Removes the tab at the specified index.
  624.      * The currently shown tab cannot be removed.
  625.      * @param index the zero-relative index of the tab to remove
  626.      */
  627.     public void removeTab(int index)
  628.     {
  629.         if ((index < 0) || (index >= vEnabled.size()) || index == curIndex)
  630.             return;
  631.  
  632.         try
  633.         {
  634.             vLabels.removeElementAt(index);
  635.             vEnabled.removeElementAt(index);
  636.             triggerRepaint();
  637.         }
  638.         catch (ArrayIndexOutOfBoundsException e) {}
  639.     }
  640.  
  641.     /**
  642.      * Removes all tabs.
  643.      */
  644.     public void removeAllTabs()
  645.     {
  646.         vLabels = new Vector();
  647.         vEnabled = new Vector();
  648.         vPolys = new Vector();
  649.         curIndex = -1;
  650.         firstVisibleTab = 0;
  651.         lastWidth = -1;
  652.         removeAll();
  653.         triggerRepaint();
  654.     }
  655.  
  656.     /**
  657.      * Handles the laying out of components within this component.
  658.      * This is a standard Java AWT method which gets called by the AWT
  659.      * when this component is validated with the validate() method.
  660.      *
  661.      * @see java.awt.Container#validate
  662.      */
  663.     public void layout()
  664.     {
  665.         Rectangle r = bounds();
  666.  
  667.         int width = r.width - TF_LEFT + TF_RIGHT;
  668.         if (width < 0)
  669.             return;
  670.  
  671.         int height = r.height - TF_TOP + TF_BOTTOM;
  672.         if (height < 0)
  673.             return;
  674.  
  675.         int col = TF_LEFT;
  676.         int row = 0;
  677.  
  678.         if (iTabsPosition == TOP)
  679.             row = TF_TOP;
  680.         else
  681.             row = TF_TOP - TF_BTN_HEIGHT;
  682.  
  683.         if (userPanel != null)
  684.         {
  685.             userPanel.reshape(col + 3, row + 3, width-6, height-5);
  686.             userPanel.invalidate();
  687.             userPanel.validate();
  688.             if (userPanel instanceof Canvas || userPanel instanceof Panel)
  689.             {
  690.                 userPanel.repaint();
  691.             }
  692.             else
  693.             {
  694.                 triggerRepaint();
  695.             }
  696.  
  697.         }
  698.     }
  699.  
  700.     /**
  701.      * Paints this component using the given graphics context.
  702.      * This is a standard Java AWT method which typically gets called
  703.      * by the AWT to handle painting this component. It paints this component
  704.      * using the given graphics context. The graphics context clipping region
  705.      * is set to the bounding rectangle of this component and its [0,0]
  706.      * coordinate is this component's top-left corner.
  707.      *
  708.      * @param g the graphics context used for painting
  709.      * @see java.awt.Component#repaint
  710.      * @see java.awt.Component#update
  711.      */
  712.     public synchronized void paint(Graphics g)
  713.     {
  714.         Rectangle r = bounds();
  715.  
  716.         //Make sure cached colors are correct.
  717.         Color curForeground = getForeground();
  718.         Color curBackground = getBackground();
  719.  
  720.         if (!symantec.itools.util.GeneralUtils.objectsEqual(curForeground, cachedForeground))
  721.         {
  722.             cachedForeground = curForeground;
  723.             calculateDisabledTextColor(curForeground);
  724.         }
  725.  
  726.         if (!symantec.itools.util.GeneralUtils.objectsEqual(curBackground, cachedBackground))
  727.         {
  728.             cachedBackground = curBackground;
  729.             calculateBorderColors(curBackground);
  730.         }
  731.  
  732.         // --------------------------------------------------------------------------------
  733.         // paint the box
  734.         // --------------------------------------------------------------------------------
  735.  
  736.         int width = r.width - TF_LEFT + TF_RIGHT;
  737.         if (width < 0)
  738.             return;
  739.  
  740.         int height = r.height - TF_TOP + TF_BOTTOM;
  741.         if (height < 0)
  742.             return;
  743.  
  744.         if (r.width > lastWidth)
  745.             firstVisibleTab = 0;
  746.         lastWidth = r.width;
  747.  
  748.         int col = TF_LEFT;
  749.         int row;
  750.  
  751.         Color c = g.getColor();
  752.         g.setColor(curBackground);
  753.         g.fillRect(0, 0, r.width, r.height);
  754.  
  755.         if (iTabsPosition == TOP)
  756.             row = TF_TOP;
  757.         else
  758.             row = TF_TOP - TF_BTN_HEIGHT;
  759.  
  760.         // --------------------------------------------------------------------------------
  761.         // draw border
  762.         // --------------------------------------------------------------------------------
  763.         g.setColor(borderLightColor);
  764.         g.drawLine(col, row, (col + width - 1), row);
  765.         g.drawLine(col, row, col, (row + height - 1));
  766.  
  767.         g.setColor(borderDarkColor);
  768.         g.drawLine((col + 2), (row + height - 2), (col + width - 2), (row + height - 2));
  769.         g.drawLine((col + width - 2), (row + 2), (col + width - 2), (row + height - 2));
  770.  
  771.         g.setColor(borderDarkerColor);
  772.         g.drawLine((col + 1), (row + height - 1), (col + width - 1), (row + height - 1));
  773.         g.drawLine((col + width - 1), (row + 1), (col + width - 1), (row + height - 1));
  774.  
  775.         // --------------------------------------------------------------------------------
  776.         // paint the tabs, and record areas
  777.         // --------------------------------------------------------------------------------
  778.         int x1;
  779.         int x2 = TF_LEFT + 8;
  780.         int y1;
  781.         int y2;
  782.         int x3 = 0;
  783.         int x4 = TF_LEFT;
  784.  
  785.         int sze = vLabels.size();
  786.         String sLabel;
  787.         vPolys.removeAllElements();
  788.  
  789.         Font f = g.getFont();
  790.         if (f != null)
  791.         {
  792.             //make sure the font size get changed
  793.             int fontSize = f.getSize();
  794.  
  795.             if(fontSize != fReg.getSize())
  796.                 fReg = new Font(fReg.getName(), fReg.getStyle(), fontSize);
  797.  
  798.             if(fontSize != fSel.getSize())
  799.                 fSel = new Font(fSel.getName(), fSel.getStyle(), fontSize);
  800.         }
  801.  
  802.         FontMetrics fm = getFontMetrics(fReg);
  803.         FontMetrics fms = getFontMetrics(fSel);
  804.         int labelWidth = 0;
  805.         Polygon p;
  806.  
  807.         int w;
  808.         // make sure there is a polygon for each tab
  809.         for (w = 0; w < firstVisibleTab; w++)
  810.         {
  811.             vPolys.addElement(nullPoly);
  812.         }
  813.  
  814.         if (w > 0)
  815.             x4 += 2;
  816.  
  817.         for (; w < sze; w++)
  818.         {
  819.             p = new Polygon();
  820.  
  821.             try
  822.             {
  823.                 sLabel = (String) vLabels.elementAt(w);
  824.  
  825.                 if (w == curIndex)
  826.                     labelWidth = fms.stringWidth(sLabel);
  827.                 else
  828.                     labelWidth = fm.stringWidth(sLabel);
  829.  
  830.                 if (iTabsPosition == TOP)
  831.                 {
  832.                     y1 = TF_TOP - TF_BTN_HEIGHT;
  833.                     y2 = TF_TOP - 1;
  834.                 }
  835.                 else
  836.                 {
  837.                     y1 = r.height + TF_BOTTOM + 1;
  838.                     y2 = r.height + TF_BOTTOM - TF_BTN_HEIGHT;
  839.                 }
  840.  
  841.                 if (iTabsStyle == ROUNDED)
  842.                 {
  843.                     x1 = x4 + 2;
  844.                     x2 = x1 + labelWidth + 13;
  845.                 }
  846.                 else
  847.                 {
  848.                     x1 = x2 - 7;
  849.                     x2 = x1 + labelWidth + 28;
  850.                 }
  851.  
  852.                 // check to see if this tab would draw too far
  853.                 if ( (x2 + 36 - TF_RIGHT) > r.width )
  854.                     break;
  855.  
  856.                 // draw the outside edge of the tab
  857.                 if (iTabsPosition == TOP)
  858.                 {
  859.                     // if current tab, it extends further
  860.                     if (w == curIndex)
  861.                     {
  862.                         y1 -= 3;
  863.                         x1 -= 2;
  864.                     }
  865.  
  866.                     g.setColor(borderLightColor);
  867.  
  868.                     if (curIndex == (w + 1))
  869.                         g.drawLine(x1+2, y1, x2-2, y1);
  870.                     else
  871.                         g.drawLine(x1+2, y1, x2, y1);
  872.  
  873.                     // draw the border between tabs if not covered by the current one
  874.                     if (curIndex != (w - 1))
  875.                     {
  876.                         g.drawLine(x1, y1+2, x1, y2);
  877.                         x3 = x1;
  878.                     }
  879.                     else
  880.                         x3 = x1 + 1;
  881.  
  882.                     g.drawLine(x1+1, y1+1, x1+1, y1+1);
  883.  
  884.                     if (curIndex != (w + 1))
  885.                     {
  886.                         g.setColor(borderDarkColor);
  887.                         g.drawLine(x2, y1, x2, y2);
  888.                         g.setColor(borderDarkerColor);
  889.                         g.drawLine(x2+1, y1+2, x2+1, y2);
  890.                         x4 = x2;
  891.                     }
  892.                     else
  893.                         x4 = x2 - 1;
  894.                 }
  895.                 else
  896.                 {
  897.                     if (iTabsStyle == SQUARE)
  898.                     {
  899.                         g.setColor(borderDarkColor);
  900.                         g.drawLine(x1+9, y1, x2-9, y1);
  901.  
  902.                         g.setColor(borderDarkerColor);
  903.                         // left \ slanted line
  904.                         if (w == 0 || w == curIndex)
  905.                         {
  906.                             g.drawLine(x1, y2, x1+9, y1);
  907.                             p.addPoint(x1, y2);
  908.                         }
  909.                         else
  910.                         {
  911.                             g.drawLine(x1+4, y1-9, x1+9, y1);
  912.                             p.addPoint(x1+9, y2);
  913.                             p.addPoint(x1+4, y1-9);
  914.                         }
  915.                         p.addPoint(x1+9, y1);
  916.                         p.addPoint(x2-9, y1);
  917.  
  918.                         if ((w+1) == curIndex)
  919.                         {
  920.                             g.drawLine(x2-5, y1-9, x2-9, y1);
  921.                             p.addPoint(x2-5, y1);
  922.                             p.addPoint(x2-9, y2);
  923.                         }
  924.                         else
  925.                         {
  926.                             g.drawLine(x2, y2, x2-9, y1);
  927.                             p.addPoint(x2, y2);
  928.                         }
  929.  
  930.                         if (w == 1 || w == curIndex)
  931.                             p.addPoint(x1, y2);
  932.                         else
  933.                             p.addPoint(x1+9, y2);
  934.                     }
  935.                     else
  936.                     {
  937.                         // if current tab, it extends further
  938.                         if (w == curIndex)
  939.                         {
  940.                             y1 += 3;
  941.                             x1 -= 2;
  942.                         }
  943.                         g.setColor(borderLightColor);
  944.                         if (curIndex == (w + 1))
  945.                             g.drawLine(x1+2, y1, x2-2, y1);
  946.                         else
  947.                             g.drawLine(x1+2, y1, x2, y1);
  948.  
  949.                         // draw the border between tabs if not covered by the current one
  950.                         if (curIndex != (w - 1))
  951.                         {
  952.                             g.drawLine(x1, y1-2, x1, y2);
  953.                             x3 = x1;
  954.                         }
  955.                         else
  956.                             x3 = x1 + 1;
  957.  
  958.                         g.drawLine(x1+1, y1-1, x1+1, y1-1);
  959.  
  960.                         if (curIndex != (w + 1))
  961.                         {
  962.                             g.setColor(borderDarkColor);
  963.                             g.drawLine(x2, y1, x2, y2);
  964.                             g.setColor(borderDarkerColor);
  965.                             g.drawLine(x2+1, y1-2, x2+1, y2);
  966.                             x4 = x2;
  967.                         }
  968.                         else
  969.                             x4 = x2 - 1;
  970.                     }
  971.                 }
  972.  
  973.                 // draw the inside edge of the tab
  974.                 if (w == curIndex)
  975.                 {
  976.                     if (iTabsPosition == TOP)
  977.                         y2++;
  978.                     else
  979.                         y2--;
  980.                     g.setColor(curBackground);
  981.                     g.drawLine(x1+1, y2, x2, y2);
  982.                     if (iTabsPosition == BOTTOM)
  983.                         g.drawLine(x1+1, y2-1, x2, y2-1);
  984.  
  985.                     g.setFont(fSel);
  986.                 }
  987.                 else
  988.                     g.setFont(fReg);
  989.  
  990.                 // if (iTabsPosition == TOP)
  991.                 if (iTabsStyle == ROUNDED)
  992.                 {
  993.                     p.addPoint(x3, y2);
  994.                     p.addPoint(x4, y2);
  995.                     p.addPoint(x4, y1);
  996.                     p.addPoint(x3, y1);
  997.                     p.addPoint(x3, y2);
  998.                 }
  999.                 vPolys.addElement(p);
  1000.  
  1001.                 Boolean bool = (Boolean) vEnabled.elementAt(w);
  1002.                 if (bool.booleanValue())
  1003.                     g.setColor(curForeground);
  1004.                 else
  1005.                     g.setColor(disabledTextColor);
  1006.  
  1007.                 if (iTabsPosition == TOP)
  1008.                     g.drawString(sLabel, x1+8, y1+15+osAdjustment);
  1009.                 else
  1010.                 {
  1011.                     if (iTabsStyle == ROUNDED)
  1012.                         g.drawString(sLabel, x1+8, y1-6+osAdjustment);
  1013.                     else
  1014.                         g.drawString(sLabel, x1+14, y1-4+osAdjustment);
  1015.                 }
  1016.             }
  1017.             catch (ArrayIndexOutOfBoundsException e) {}
  1018.         }
  1019.  
  1020.         // do I need to show arrows because there are too many tabs???
  1021.         if ( (firstVisibleTab > 0) || (w < sze) )
  1022.         {
  1023.             dbLeft.show();
  1024.             dbRight.show();
  1025.             if (firstVisibleTab > 0)
  1026.                 dbLeft.setEnabled(true);
  1027.             else
  1028.                 dbLeft.setEnabled(false);
  1029.  
  1030.             if (w < sze)
  1031.                 dbRight.setEnabled(true);
  1032.             else
  1033.                 dbRight.setEnabled(false);
  1034.  
  1035.             if (iTabsPosition == TOP)
  1036.             {
  1037.                 dbLeft.reshape(r.width-33+TF_RIGHT, TF_TOP - 16, 16, 15);
  1038.                 dbRight.reshape(r.width-16+TF_RIGHT, TF_TOP - 16, 16, 15);
  1039.             }
  1040.             else
  1041.             {
  1042.                 dbLeft.reshape(r.width-33+TF_RIGHT, r.height + TF_BOTTOM - TF_BTN_HEIGHT, 16, 15);
  1043.                 dbRight.reshape(r.width-16+TF_RIGHT, r.height + TF_BOTTOM - TF_BTN_HEIGHT, 16, 15);
  1044.             }
  1045.         }
  1046.         else
  1047.         {
  1048.             dbLeft.hide();
  1049.             dbRight.hide();
  1050.         }
  1051.  
  1052.         // make sure there is a polygon for each tab
  1053.         for (; w < sze; w++)
  1054.         {
  1055.             vPolys.addElement(nullPoly);
  1056.         }
  1057.  
  1058.         g.setFont(f);
  1059.         g.setColor(c);
  1060.     }
  1061.  
  1062.  
  1063.     // ===========================================================
  1064.     // Component functions overridden so user cannot change the
  1065.     // way this container should work
  1066.     // ===========================================================
  1067.     /**
  1068.      * Takes no action, use addTab().
  1069.      * This is a standard Java AWT method which gets called to add a
  1070.      * component to a container.
  1071.      * It is overridden here to do nothing, so the user cannot change the way
  1072.      * this container works. Use setPanel, showPanel, addTab, and setTab
  1073.      * instead.
  1074.      *
  1075.      * @param comp the component to add (IGNORED)
  1076.      * @return the component parameter
  1077.      * @see #setPanel
  1078.      * @see #showPanel
  1079.      * @see #addTab
  1080.      * @see #setTab
  1081.      * @see #remove
  1082.      */
  1083.     public Component add(Component comp) { return comp; }
  1084.     /**
  1085.      * Takes no action, use addTab().
  1086.      * This is a standard Java AWT method which gets called to add a
  1087.      * component to a container.
  1088.      * It is overridden here to do nothing, so the user cannot change the way
  1089.      * this container works. Use setPanel, showPanel, addTab, and setTab
  1090.      * instead.
  1091.      *
  1092.      * @param comp the component to add (IGNORED)
  1093.      * @param pos the zero-relative index at which to add the component or -1
  1094.      * for end (IGNORED)
  1095.      * @return the component parameter
  1096.      * @see #setPanel
  1097.      * @see #showPanel
  1098.      * @see #addTab
  1099.      * @see #setTab
  1100.      * @see #remove
  1101.      */
  1102.     public synchronized Component add(Component comp, int pos) { return comp; }
  1103.     /**
  1104.      * Takes no action, use addTab().
  1105.      * This is a standard Java AWT method which gets called to add a
  1106.      * component to a container.
  1107.      * It is overridden here to do nothing, so the user cannot change the way
  1108.      * this container works. Use setPanel, showPanel, addTab, and setTab
  1109.      * instead.
  1110.      *
  1111.      * @param name the positioning directive for the layout manager (IGNORED)
  1112.      * @param comp the component to add (IGNORED)
  1113.      * @return the component parameter
  1114.      * @see #setPanel
  1115.      * @see #showPanel
  1116.      * @see #addTab
  1117.      * @see #setTab
  1118.      * @see #remove
  1119.      */
  1120.     public synchronized Component add(String name, Component comp) { return comp; }
  1121.  
  1122.     /**
  1123.      * Removes the specified component from this container.
  1124.      * This is a standard Java AWT method which gets called to remove a
  1125.      * component from a container. When this happens the component's
  1126.      * removeNotify() will also get called to indicate component removal.
  1127.      *
  1128.      * @param comp the component to remove
  1129.      * @see #removeAll
  1130.      * @see #addTab
  1131.      */
  1132.     public synchronized void remove(Component comp)
  1133.     {
  1134.         if (comp == dbLeft || comp == dbRight)
  1135.             return;
  1136.            super.remove(comp);
  1137.         if (comp == (Component) userPanel)
  1138.                userPanel = null;
  1139.     }
  1140.  
  1141.     /**
  1142.      * Removes all the components from this container.
  1143.      * This is a standard Java AWT method which gets called to remove all
  1144.      * the components from a container. When this happens each component's
  1145.      * removeNotify() will also get called to indicate component removal.
  1146.      *
  1147.      * @see #remove
  1148.      * @see #addTab
  1149.      */
  1150.     public synchronized void removeAll()
  1151.     {
  1152.         super.removeAll();
  1153.         super.add(dbLeft, -1);
  1154.         super.add(dbRight, -1);
  1155.         userPanel = null;
  1156.     }
  1157.  
  1158.     /**
  1159.      * Takes no action.
  1160.      * This is a standard Java AWT method which gets called to specify
  1161.      * which layout manager should be used to layout the components in
  1162.      * standard containers.
  1163.      *
  1164.      * Since layout managers CANNOT BE USED with this container the standard
  1165.      * setLayout has been OVERRIDDEN for this container and does nothing.
  1166.      *
  1167.      * @param mgr the layout manager to use to layout this container's components
  1168.      * (IGNORED)
  1169.      * @see java.awt.Container#getLayout
  1170.      **/
  1171.     public void setLayout(LayoutManager mgr) {}
  1172.  
  1173.     /**
  1174.      * Returns the amount of space used by the current border.
  1175.      * This is a standard Java AWT method which gets called to determine
  1176.      * the size of the current border. The returned value is the width
  1177.      * of each border side in pixels.
  1178.      *
  1179.      * @return the current border insets
  1180.      */
  1181.     public Insets insets()
  1182.     {
  1183.         btpInsets = super.insets();
  1184.         btpInsets.left += (TF_LEFT + 3);
  1185.         btpInsets.right += (6 - TF_RIGHT);
  1186.  
  1187.         if (iTabsPosition == TOP)
  1188.         {
  1189.             btpInsets.top += (TF_TOP + 3);
  1190.             btpInsets.bottom += (5 - TF_BOTTOM);
  1191.         }
  1192.         else
  1193.         {
  1194.             btpInsets.top += TF_TOP - TF_BTN_HEIGHT + 3;
  1195.             btpInsets.bottom += (TF_BTN_HEIGHT + 5 - TF_BOTTOM);
  1196.         }
  1197.  
  1198.         return btpInsets;
  1199.     }
  1200.  
  1201.     /**
  1202.      * Returns the recommended dimensions to properly display this component.
  1203.      * This is a standard Java AWT method which gets called to determine
  1204.      * the recommended size of this component.
  1205.      *
  1206.      * @see #getMinimumSize
  1207.      */
  1208.     public Dimension getPreferredSize()
  1209.     {
  1210.         Dimension s = size();
  1211.         Dimension m = minimumSize();
  1212.         return new Dimension(Math.max(s.width, m.width), Math.max(s.height, m.height));
  1213.     }
  1214.  
  1215.     /**
  1216.      * @deprecated
  1217.      * @see #getPreferredSize
  1218.      */
  1219.     public Dimension preferredSize()
  1220.     {
  1221.         return getPreferredSize();
  1222.     }
  1223.  
  1224.     /**
  1225.      * Returns the minimum dimensions to properly display this component.
  1226.      * This is a standard Java AWT method which gets called to determine
  1227.      * the minimum size of this component.
  1228.      *
  1229.      * @see #getPreferredSize
  1230.      */
  1231.     public Dimension getMinimumSize()
  1232.     {
  1233.         if (userPanel != null)
  1234.         {
  1235.             Dimension s = userPanel.minimumSize();
  1236.             return new Dimension(    (s.width + btpInsets.left + btpInsets.right),
  1237.                                     (s.height + btpInsets.top + btpInsets.bottom) );
  1238.         }
  1239.         return new Dimension(100, 100);
  1240.     }
  1241.  
  1242.     /**
  1243.      * @deprecated
  1244.      * @see #getMinimumSize
  1245.      */
  1246.     public Dimension minimumSize()
  1247.     {
  1248.         return getMinimumSize();
  1249.     }
  1250.  
  1251.     /**
  1252.      * Tells this component that it has been added to a container.
  1253.      * This is a standard Java AWT method which gets called by the AWT when
  1254.      * this component is added to a container. Typically, it is used to
  1255.      * create this component's peer.
  1256.      *
  1257.      * It has been overridden here to hook-up event listeners.
  1258.      *
  1259.      * @see #removeNotify
  1260.      */
  1261.     public synchronized void addNotify()
  1262.     {
  1263.         super.addNotify();
  1264.  
  1265.         //Hook up listeners
  1266.         if (mouse == null)
  1267.         {
  1268.             mouse = new Mouse();
  1269.             addMouseListener(mouse);
  1270.         }
  1271.         if (action == null)
  1272.         {
  1273.             action = new Action();
  1274.             dbLeft.addActionListener(action);
  1275.             dbRight.addActionListener(action);
  1276.         }
  1277.     }
  1278.  
  1279.     /**
  1280.      * Tells this component that it is being removed from a container.
  1281.      * This is a standard Java AWT method which gets called by the AWT when
  1282.      * this component is removed from a container. Typically, it is used to
  1283.      * destroy the peers of this component and all its subcomponents.
  1284.      *
  1285.      * It has been overridden here to unhook event listeners.
  1286.      *
  1287.      * @see #addNotify
  1288.      */
  1289.     public synchronized void removeNotify()
  1290.     {
  1291.         //Unhook listeners
  1292.         if (mouse != null)
  1293.         {
  1294.             removeMouseListener(mouse);
  1295.             mouse = null;
  1296.         }
  1297.         if (action != null)
  1298.         {
  1299.             dbLeft.removeActionListener(action);
  1300.             dbRight.removeActionListener(action);
  1301.             action = null;
  1302.         }
  1303.  
  1304.         super.removeNotify();
  1305.     }
  1306.  
  1307.     // ===========================================================
  1308.     // Done Component functions overridden
  1309.     // ===========================================================
  1310.  
  1311.     /**
  1312.      * Adds a listener for all property changes.
  1313.      * @param listener the listener to add.
  1314.      * @see #removePropertyChangeListener
  1315.      */
  1316.     public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
  1317.     {
  1318.         changes.addPropertyChangeListener(listener);
  1319.     }
  1320.  
  1321.     /**
  1322.      * Removes a listener for all property changes.
  1323.      * @param listener the listener to remove.
  1324.      * @see #addPropertyChangeListener
  1325.      */
  1326.     public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
  1327.     {
  1328.         changes.removePropertyChangeListener(listener);
  1329.     }
  1330.  
  1331.     /**
  1332.      * Adds a vetoable listener for all property changes.
  1333.      * @param listener the listener to add.
  1334.      * @see #removeVetoableChangeListener
  1335.      */
  1336.     public synchronized void addVetoableChangeListener(VetoableChangeListener listener)
  1337.     {
  1338.         vetos.addVetoableChangeListener(listener);
  1339.     }
  1340.  
  1341.     /**
  1342.      * Removes a vetoable listener for all property changes.
  1343.      * @param listener the listener to remove.
  1344.      * @see #addVetoableChangeListener
  1345.      */
  1346.     public synchronized void removeVetoableChangeListener(VetoableChangeListener listener)
  1347.     {
  1348.         vetos.removeVetoableChangeListener(listener);
  1349.     }
  1350.  
  1351.     /**
  1352.      * Adds a listener for the CurrentTab property changes.
  1353.      * @param listener the listener to add.
  1354.      * @see #removePropertyChangeListener
  1355.      */
  1356.     public synchronized void addCurrentTabListener(PropertyChangeListener listener)
  1357.     {
  1358.         changes.addPropertyChangeListener("CurrentTab", listener);
  1359.     }
  1360.  
  1361.     /**
  1362.      * Removes a listener for the CurrentTab property changes.
  1363.      * @param listener the listener to remove.
  1364.      * @see #addPropertyChangeListener
  1365.      */
  1366.     public synchronized void removeCurrentTabListener(PropertyChangeListener listener)
  1367.     {
  1368.         changes.removePropertyChangeListener("CurrentTab", listener);
  1369.     }
  1370.  
  1371.     /**
  1372.      * Adds a vetoable listener for the CurrentTab property changes.
  1373.      * @param listener the listener to add.
  1374.      * @see #removeVetoableChangeListener
  1375.      */
  1376.     public synchronized void addCurrentTabListener(VetoableChangeListener listener)
  1377.     {
  1378.         vetos.addVetoableChangeListener("CurrentTab", listener);
  1379.     }
  1380.  
  1381.     /**
  1382.      * Removes a vetoable listener for the CurrentTab property changes.
  1383.      * @param listener the listener to remove.
  1384.      * @see #addVetoableChangeListener
  1385.      */
  1386.     public synchronized void removeCurrentTabListener(VetoableChangeListener listener)
  1387.     {
  1388.         vetos.removeVetoableChangeListener("CurrentTab", listener);
  1389.     }
  1390.  
  1391.     /**
  1392.      * This is the Mouse Event handling innerclass.
  1393.      */
  1394.     class Mouse extends java.awt.event.MouseAdapter implements java.io.Serializable
  1395.     {
  1396.         public void mousePressed(MouseEvent e)
  1397.         {
  1398.             int sizeR = vPolys.size();
  1399.             Polygon p;
  1400.             for (int x = 0; x < sizeR; x++)
  1401.             {
  1402.                 try
  1403.                 {
  1404.                     p = (Polygon) vPolys.elementAt(x);
  1405.                     if ( (p != nullPoly) && p.inside(e.getX(), e.getY()) )
  1406.                     {
  1407.                         try
  1408.                         {
  1409.                             setCurrentTab(x);
  1410.                         }
  1411.                         catch(PropertyVetoException exc){}
  1412.                     }
  1413.                 }
  1414.                 catch (ArrayIndexOutOfBoundsException exc){}
  1415.             }
  1416.         }
  1417.     }
  1418.  
  1419.  
  1420.     /**
  1421.      * This is the Action Event handling innerclass.
  1422.      */
  1423.     class Action implements java.awt.event.ActionListener, java.io.Serializable
  1424.     {
  1425.         public void actionPerformed(ActionEvent e)
  1426.         {
  1427.             if (e.getSource() == dbLeft)
  1428.             {
  1429.                 if (--firstVisibleTab < 0)
  1430.                     firstVisibleTab = 0;
  1431.                 else
  1432.                     triggerRepaint();
  1433.             }
  1434.             else if (e.getSource() == dbRight)
  1435.             {
  1436.                 int sze = vLabels.size();
  1437.                 if (++firstVisibleTab == sze)
  1438.                     firstVisibleTab--;
  1439.                 else
  1440.                     triggerRepaint();
  1441.             }
  1442.         }
  1443.     }
  1444.  
  1445.     /**
  1446.      * Used to calculate the border colors from the background color.
  1447.      * @see #paint
  1448.      */
  1449.     protected void calculateBorderColors(Color c)
  1450.     {
  1451.         borderLightColor    = ColorUtils.calculateHilightColor(c);
  1452.         borderDarkColor        = ColorUtils.calculateShadowColor(c);
  1453.         borderDarkerColor    = ColorUtils.darken(borderDarkColor, 0.200);
  1454.     }
  1455.  
  1456.     /**
  1457.      * Used to calculate the disabled text color from the foreground color.
  1458.      * @see #paint
  1459.      */
  1460.     protected void calculateDisabledTextColor(Color c)
  1461.     {
  1462.         try
  1463.         {
  1464.             disabledTextColor = ColorUtils.fade(c, Color.lightGray, 0.50);
  1465.         }
  1466.         catch (IllegalArgumentException exc) {}
  1467.     }
  1468.  
  1469.     /**
  1470.      * Zero-relative index of currently shown tab. -1 if no tabs exist or are shown.
  1471.      */
  1472.     protected int curIndex = -1;
  1473.  
  1474.     /**
  1475.      * A flag indicating repaints should be suppress during the setLabel()
  1476.      * and setEnabled() methods.
  1477.      */
  1478.     transient protected boolean suppressRepaints = false;
  1479.     /**
  1480.      * A Vector of Polygons, one for each tab.
  1481.      */
  1482.     protected Vector vPolys;
  1483.     /**
  1484.      * The zero-relative index of the first visible tab.
  1485.      */
  1486.     protected int firstVisibleTab = 0;
  1487.     /**
  1488.      * A left-pointing button shown when there are too many tabs to display.
  1489.      */
  1490.     protected DirectionButton dbLeft;
  1491.     /**
  1492.      * A right-pointing button shown when there are too many tabs to display.
  1493.      */
  1494.     protected DirectionButton dbRight;
  1495.     /**
  1496.      * An empty polygon.
  1497.      */
  1498.     protected Polygon nullPoly;
  1499.     /**
  1500.      * A Vector of tab label Strings.
  1501.      */
  1502.     protected Vector vLabels;
  1503.     /**
  1504.      * Color used in drawing of the border.
  1505.      */
  1506.     protected Color borderDarkerColor    = null;
  1507.     /**
  1508.      * Color used in drawing of the border.
  1509.      */
  1510.     protected Color borderLightColor    = null;
  1511.     /**
  1512.      * Color used in drawing of the border.
  1513.      */
  1514.     protected Color borderDarkColor    = null;
  1515.     /**
  1516.      * Color used in drawing of the disabled text.
  1517.      */
  1518.     protected Color disabledTextColor    = null;
  1519.     /**
  1520.      * Cached value of the foreground color.  Used to determine if calculated colors need to be updated.
  1521.      */
  1522.     protected Color cachedForeground    = null;
  1523.     /**
  1524.      * Cached value of the background color.  Used to determine if calculated colors need to be updated.
  1525.      */
  1526.     protected Color cachedBackground    = null;
  1527.  
  1528.     /**
  1529.      * Internal tab margin constant.
  1530.      */
  1531.     protected int TF_LEFT = 9;
  1532.     /**
  1533.      * Internal tab margin constant.
  1534.      */
  1535.     protected int TF_RIGHT = -9;
  1536.     /**
  1537.      * Internal tab margin constant.
  1538.      */
  1539.     protected int TF_TOP = 30;
  1540.     /**
  1541.      * Internal tab margin constant.
  1542.      */
  1543.     protected int TF_BOTTOM = -9;
  1544.     /**
  1545.      * Internal tab margin constant.
  1546.      */
  1547.     protected int TF_BTN_HEIGHT = 20;
  1548.  
  1549.     private Vector vEnabled;
  1550.  
  1551.     /**
  1552.      * The font used for drawing tab titles when they are not selected.
  1553.      */
  1554.     protected Font fReg;
  1555.     /**
  1556.      * The font used for drawing tab titles when they are selected.
  1557.      */
  1558.     protected Font fSel;
  1559.  
  1560.     private Component userPanel = null;
  1561.  
  1562.     private int iTabsPosition = TOP;
  1563.     private int iTabsStyle = ROUNDED;
  1564.  
  1565.     transient private int osAdjustment;
  1566.  
  1567.     private int lastWidth = -1;
  1568.  
  1569.     private Insets btpInsets;
  1570.  
  1571.     private Mouse    mouse    = null;
  1572.     private Action    action    = null;
  1573.     private symantec.itools.beans.VetoableChangeSupport vetos   = new symantec.itools.beans.VetoableChangeSupport(this);
  1574.     private symantec.itools.beans.PropertyChangeSupport changes = new symantec.itools.beans.PropertyChangeSupport(this);
  1575.  
  1576.  
  1577.     /**
  1578.      * Determines the first tab that must be visible in order to make
  1579.      * the given tab visible.
  1580.      * @param index the zero-relative tab index
  1581.      * @return the zero-relative index of the first visible tab
  1582.      */
  1583.     protected int calculateMakeTabVisible(int index)
  1584.     {
  1585.         Rectangle   bounds;
  1586.         Vector      tabSizes;
  1587.         int         width;
  1588.         int         height;
  1589.         int         fontSize;
  1590.         FontMetrics fmUnselected;
  1591.         FontMetrics fmSelected;
  1592.  
  1593.         // optimize the obvious case
  1594.         if(index == 0)
  1595.         {
  1596.             return (0);
  1597.         }
  1598.  
  1599.         // if all of the tabs are visible then no point in
  1600.         // doing anything
  1601.         if(!(dbLeft.isVisible()) && !(dbRight.isVisible()))
  1602.         {
  1603.             return (0);
  1604.         }
  1605.  
  1606.         bounds = getBounds();
  1607.         width  = bounds.width - btpInsets.left - btpInsets.right -
  1608.                  dbLeft.getBounds().width - dbRight.getBounds().width -
  1609.                  TF_LEFT + TF_RIGHT;
  1610.  
  1611.         // too small to show anything?
  1612.         if(width < 0)
  1613.         {
  1614.             return (0);
  1615.         }
  1616.  
  1617.         Font f = getFont();
  1618.         if (f != null)
  1619.         {
  1620.             fontSize = f.getSize();
  1621.  
  1622.             if(fontSize != fReg.getSize())
  1623.             {
  1624.                 fReg = new Font(fReg.getName(), fReg.getStyle(), fontSize);
  1625.             }
  1626.  
  1627.             if(fontSize != fSel.getSize())
  1628.             {
  1629.                 fSel = new Font(fSel.getName(), fSel.getStyle(), fontSize);
  1630.             }
  1631.         }
  1632.  
  1633.         fmUnselected = getFontMetrics(fReg);
  1634.         fmSelected   = getFontMetrics(fSel);
  1635.         tabSizes     = new Vector();
  1636.  
  1637.         // find the size of all of the tabs
  1638.         for(int i = 0; i < vLabels.size(); i++)
  1639.         {
  1640.             String label;
  1641.             int    labelWidth;
  1642.             int    x1;
  1643.             int    x2;
  1644.  
  1645.             label = (String)vLabels.elementAt(i);
  1646.  
  1647.             if(i != index)
  1648.             {
  1649.                 labelWidth = fmUnselected.stringWidth(label);
  1650.             }
  1651.             else
  1652.             {
  1653.                 labelWidth = fmSelected.stringWidth(label);
  1654.             }
  1655.  
  1656.             if(iTabsStyle == ROUNDED)
  1657.             {
  1658.                 x1 = TF_LEFT + 2;
  1659.                 x2 = x1 + labelWidth + 13;
  1660.             }
  1661.             else
  1662.             {
  1663.                 x1 = TF_LEFT - 7;
  1664.                 x2 = x1 + labelWidth + 28;
  1665.             }
  1666.  
  1667.             if(i == index)
  1668.             {
  1669.                 x1 -= 2;
  1670.             }
  1671.  
  1672.             tabSizes.addElement(new Integer(x2 - x1));
  1673.         }
  1674.  
  1675.         int total = 0;
  1676.  
  1677.         for(int i = 0; i <= index; i++)
  1678.         {
  1679.             total += ((Integer)tabSizes.elementAt(i)).intValue();
  1680.         }
  1681.  
  1682.         if(total < width)
  1683.         {
  1684.             return (0);
  1685.         }
  1686.  
  1687.         for(int i = index; i >= 0; i--)
  1688.         {
  1689.             int value;
  1690.  
  1691.             value = ((Integer)tabSizes.elementAt(i)).intValue();
  1692.  
  1693.             if((width - value) > 0)
  1694.             {
  1695.                 width -= value;
  1696.             }
  1697.             else
  1698.             {
  1699.                 return (i + 1);
  1700.             }
  1701.         }
  1702.  
  1703.         // should never happen
  1704.         return (0);
  1705.     }
  1706. }
  1707.